// 定义 CrossDomainBridge 类
class CrossDomainBridge {
  /**
   * 初始化通信桥
   * @param {Object} options
   * @param {string} options.role - 'parent'（父页面）或 'iframe'（iframe页面）
   * @param {string[]} options.trustedOrigins - 信任的域名列表（含端口，如['http://localhost:3000']）
   * @param {string} [options.iframeId] - iframe的唯一标识（仅iframe需要）
   * @param {string} [options.parentOrigin] - 父页面的域名（仅iframe需要，如'http://localhost:8080'）
   */
  constructor(options) {
    this.role = options.role;
    this.trustedOrigins = options.trustedOrigins;
    this.iframeId = options.iframeId;
    this.parentOrigin = options.parentOrigin;

    // 存储已注册的iframe（父页面用）
    this.iframeMap = new Map();
    // 消息监听器（key:消息类型，value:回调数组）
    this.listeners = new Map();
    this.initialized = false;

    this.init();
  }

  // 初始化：绑定message事件
  init() {
    if (this.initialized) return;
    window.addEventListener("message", (e) => this.handleMessage(e));
    this.initialized = true;
    console.log(`[通信桥] ${this.role} 初始化完成`);
  }

  // 验证消息来源是否可信
  isTrusted(origin) {
    return (
      this.trustedOrigins.includes(origin) ||
      this.trustedOrigins.includes("*")
    );
  }

  // 处理接收到的消息
  handleMessage(event) {
    const { origin, data, source } = event;
    // 验证来源
    if (!this.isTrusted(origin)) {
      console.warn(`[通信桥] 拒绝不可信域名 ${origin} 的消息`);
      return;
    }
    // 验证消息格式
    if (!data || !data.type || !data.sender || !data.target) {
      console.warn(`[通信桥] 无效消息格式:`, data);
      return;
    }

    const { type, sender, target, payload } = data;
    
    // 父页面逻辑：转发消息或处理自身消息
    if (this.role === "parent") {
      // 处理iframe注册
      if (type === "__IFRAME_REGISTER__") {
        this.iframeMap.set(payload.iframeId, { origin, source });
        console.log(
          `[通信桥] 已注册iframe: ${payload.iframeId}（${origin}）`
        );
        return;
      }
      // 转发消息给目标iframe
      if (target !== "parent" && this.iframeMap.has(target)) {
        const targetIframe = this.iframeMap.get(target);
        targetIframe.source.postMessage(data, targetIframe.origin);
        return;
      }
      // 父页面自身消息
      if (target === "parent" && this.listeners.has(type)) {
        this.listeners
          .get(type)
          .forEach((cb) => cb(payload, sender, origin));
      }
    }

    // iframe逻辑：只处理目标为自己或全体的消息
    if (this.role === "iframe") {
      if (target === this.iframeId || target === "*") {
        if (this.listeners.has(type)) {
          this.listeners
            .get(type)
            .forEach((cb) => cb(payload, sender, origin));
        }
      }
    }
  }

  // 发送消息
  send({ target, type, payload }) {
    if (!this.initialized) {
      console.error(`[通信桥] 未初始化`);
      return;
    }
    const message = {
      sender: this.role === "parent" ? "parent" : this.iframeId,
      target,
      type,
      payload,
      timestamp: Date.now(),
    };

    // 父页面发送：直接发给目标iframe或广播
    if (this.role === "parent") {
      if (target === "*") {
        this.iframeMap.forEach((iframe) => {
          iframe.source.postMessage(message, iframe.origin);
        });
        return;
      }
      if (this.iframeMap.has(target)) {
        const targetIframe = this.iframeMap.get(target);
        targetIframe.source.postMessage(message, targetIframe.origin);
        return;
      }
      console.warn(`[通信桥] 目标iframe ${target} 未注册`);
    }

    // iframe发送：只能发给父页面（由父页面中转）
    if (this.role === "iframe" && this.parentOrigin) {
      window.parent.postMessage(message, this.parentOrigin);
    }
  }

  // 监听消息
  on(type, callback) {
    if (!this.listeners.has(type)) {
      this.listeners.set(type, []);
    }
    this.listeners.get(type).push(callback);
  }

  // 取消监听
  off(type, callback) {
    if (!this.listeners.has(type)) return;
    const callbacks = this.listeners.get(type);
    const index = callbacks.indexOf(callback);
    if (index > -1) callbacks.splice(index, 1);
  }
}

// 暴露到 window 全局对象，可在页面任意位置通过 window.CrossDomainBridge 访问
window.CrossDomainBridge = CrossDomainBridge;